/* exif_lib.c - 纯C实现的EXIF写入库 */
#include "exif_lib.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "time.h"

/* 计算16位校验和 */
static uint16_t calculate_checksum(const uint8_t *data, size_t length) {
    uint16_t checksum = 0;
    for (size_t i = 0; i < length; i++) {
        checksum += data[i];
    }
    return checksum;
}

/* 转换为 Motorola 字节序 (大端) */
static uint16_t to_motorola16(uint16_t value) {
    return ((value >> 8) & 0xFF) | ((value << 8) & 0xFF00);
}

/* 从 Motorola 字节序 (大端) 转换 */
static uint16_t from_motorola16(uint16_t value) {
    return to_motorola16(value); // 对于16位，转换是对称的
}

static uint32_t to_motorola32(uint32_t value) {
    return ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) |
           ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
}

/* 创建新的EXIF条目 */
static ExifEntry* exif_entry_create(uint16_t tag, uint16_t format, 
                                  uint32_t components, const void *data, size_t dataSize) {
    ExifEntry *entry = (ExifEntry*)malloc(sizeof(ExifEntry));
    if (!entry) return NULL;
    
    entry->tag = tag;
    entry->format = format;
    entry->components = components;
    entry->data = malloc(dataSize);
    if (entry->data) {
        memcpy(entry->data, data, dataSize);
    }
    entry->dataSize = dataSize;
    entry->next = NULL;
    
    return entry;
}

/* 添加条目到IFD */

static void exif_add_entry(ExifData *data, int ifd, ExifEntry *entry) {
    if (!data || !entry) return;

    ExifEntry **head = NULL;
    switch (ifd) {
        case IFD0: head = &data->ifd0; break;
        case EXIF_IFD: head = &data->exifIfd; break;
        case GPS_IFD: head = &data->gpsIfd; break;
        default: return;
    }

    // 简单添加到链表末尾，保持添加顺序
    if (*head == NULL) {
        *head = entry;
    } else {
        ExifEntry *current = *head;
        while (current->next) {
            current = current->next;
        }
        current->next = entry;
    }
}

/* 计算格式大小 */
static size_t format_size(uint16_t format) {
    switch (format) {
        case EXIF_FORMAT_BYTE: return 1;
        case EXIF_FORMAT_ASCII: return 1;
        case EXIF_FORMAT_SHORT: return 2;
        case EXIF_FORMAT_LONG: return 4;
        case EXIF_FORMAT_RATIONAL: return 8;
        default: return 0;
    }
}

/* 计算IFD中的条目数量 */
static int count_entries(ExifEntry *head) {
    int count = 0;
    ExifEntry *current = head;
    while (current) {
        count++;
        current = current->next;
    }
    return count;
}

/* 释放条目链表 */
static void free_entries(ExifEntry *head) {
    ExifEntry *current = head;
    while (current) {
        ExifEntry *next = current->next;
        if (current->data) free(current->data);
        free(current);
        current = next;
    }
}

/* 创建新的EXIF数据 */
ExifData* exif_create() {
    ExifData *data = (ExifData*)malloc(sizeof(ExifData));
    if (data) {
        data->ifd0 = NULL;
        data->exifIfd = NULL;
        data->gpsIfd = NULL;
        data->buffer = NULL;
        data->bufferSize = 0;
    }
    return data;
}

/* 释放EXIF数据 */
void exif_destroy(ExifData *data) {
    if (data) {
        free_entries(data->ifd0);
        free_entries(data->exifIfd);
        free_entries(data->gpsIfd);
        if (data->buffer) free(data->buffer);
        free(data);
    }
}

/* 添加字符串类型的EXIF条目 */
void exif_add_string(ExifData *data, int ifd, uint16_t tag, const char *value) {
    if (!data || !value) return;
    size_t len = strlen(value) + 1; // 包含结尾\0
    printf("[EXIF_DEBUG] add string tag=0x%04x, value='%s', len=%zu\n", tag, value, len);
    char *buf = (char*)malloc(len);
    if (!buf) return;
    memcpy(buf, value, len);
    // components参数应该是字符串长度(不含null终止符)，但dataSize仍包含null终止符
    ExifEntry *entry = exif_entry_create(tag, EXIF_FORMAT_ASCII, len-1, buf, len);
    // 注意：不在这里释放buf，因为entry->data指向了这个内存
    // 内存将由exif_destroy函数释放
    if (entry) {
        exif_add_entry(data, ifd, entry);
    } else {
        // 如果创建条目失败，释放buf
        free(buf);
    }
}

/* 添加短整数类型的EXIF条目 */
void exif_add_short(ExifData *data, int ifd, uint16_t tag, uint16_t value) {
    if (!data) return;
    
    uint16_t val = to_motorola16(value);
    ExifEntry *entry = exif_entry_create(tag, EXIF_FORMAT_SHORT, 1, &val, sizeof(val));
    if (entry) {
        exif_add_entry(data, ifd, entry);
    }
}

/* 转换双精度数为分数 */
static ExifRational double_to_rational(double value, int precision) {
    ExifRational r;
    double integer_part;
    double fractional_part = modf(value, &integer_part);
    
    // 计算分母，基于精度
    uint32_t denominator = 1;
    for (int i = 0; i < precision; i++) {
        denominator *= 10;
    }
    
    // 计算分子
    r.numerator = (uint32_t)(integer_part * denominator + round(fractional_part * denominator));
    r.denominator = denominator;
    
    // 简化分数
    uint32_t gcd = 1;
    uint32_t a = r.numerator;
    uint32_t b = r.denominator;
    while (b != 0) {
        uint32_t temp = b;
        b = a % b;
        a = temp;
    }
    gcd = a;
    
    r.numerator /= gcd;
    r.denominator /= gcd;
    
    return r;
}

/* 添加GPS坐标 */
void exif_add_gps(ExifData *data, double latitude, double longitude, double altitude) {
    if (!data) return;
    
    // 纬度参考 (N/S)
    exif_add_string(data, GPS_IFD, EXIF_TAG_GPS_LAT_REF, latitude >= 0 ? "N" : "S");
    
    // 经度参考 (E/W)
    exif_add_string(data, GPS_IFD, EXIF_TAG_GPS_LON_REF, longitude >= 0 ? "E" : "W");
    
    // 海拔参考 (0 = 高于海平面, 1 = 低于海平面)
    uint8_t alt_ref = altitude >= 0 ? 0 : 1;
    ExifEntry *altRefEntry = exif_entry_create(EXIF_TAG_GPS_ALT_REF, EXIF_FORMAT_BYTE, 
                                              1, &alt_ref, sizeof(alt_ref));
    if (altRefEntry) {
        exif_add_entry(data, GPS_IFD, altRefEntry);
    }
    
    // 海拔值
    ExifRational alt = double_to_rational(fabs(altitude), 2);
    ExifRational alt_m[1];
    alt_m[0].numerator = to_motorola32(alt.numerator);
    alt_m[0].denominator = to_motorola32(alt.denominator);
    
    ExifEntry *altEntry = exif_entry_create(EXIF_TAG_GPS_ALT, EXIF_FORMAT_RATIONAL, 
                                           1, alt_m, sizeof(alt_m));
    if (altEntry) {
        exif_add_entry(data, GPS_IFD, altEntry);
    }
    
    // 处理纬度
    double lat = fabs(latitude);
    int degrees = (int)lat;
    double minutes_decimal = (lat - degrees) * 60;
    int minutes = (int)minutes_decimal;
    double seconds = (minutes_decimal - minutes) * 60;
    
    ExifRational lat_vals[3];
    lat_vals[0] = double_to_rational(degrees, 0);
    lat_vals[1] = double_to_rational(minutes, 0);
    lat_vals[2] = double_to_rational(seconds, 3);
    
    // 转换为Motorola字节序
    ExifRational lat_m[3];
    for (int i = 0; i < 3; i++) {
        lat_m[i].numerator = to_motorola32(lat_vals[i].numerator);
        lat_m[i].denominator = to_motorola32(lat_vals[i].denominator);
    }
    
    ExifEntry *latEntry = exif_entry_create(EXIF_TAG_GPS_LAT, EXIF_FORMAT_RATIONAL, 
                                           3, lat_m, sizeof(lat_m));
    if (latEntry) {
        exif_add_entry(data, GPS_IFD, latEntry);
    }
    
    // 处理经度
    double lon = fabs(longitude);
    degrees = (int)lon;
    minutes_decimal = (lon - degrees) * 60;
    minutes = (int)minutes_decimal;
    seconds = (minutes_decimal - minutes) * 60;
    
    ExifRational lon_vals[3];
    lon_vals[0] = double_to_rational(degrees, 0);
    lon_vals[1] = double_to_rational(minutes, 0);
    lon_vals[2] = double_to_rational(seconds, 3);
    
    // 转换为Motorola字节序
    ExifRational lon_m[3];
    for (int i = 0; i < 3; i++) {
        lon_m[i].numerator = to_motorola32(lon_vals[i].numerator);
        lon_m[i].denominator = to_motorola32(lon_vals[i].denominator);
    }
    
    ExifEntry *lonEntry = exif_entry_create(EXIF_TAG_GPS_LON, EXIF_FORMAT_RATIONAL, 
                                           3, lon_m, sizeof(lon_m));
    if (lonEntry) {
        exif_add_entry(data, GPS_IFD, lonEntry);
    }
}

/* 生成IFD数据 */
// 生成IFD数据，返回数据区结束偏移
static size_t generate_ifd(uint8_t *buffer, size_t offset, ExifEntry *entries,
                          size_t data_offset, int *next_ifd_offset, size_t ifd0_offset) {
    if (!buffer || !entries || !next_ifd_offset) return 0;

    int count = count_entries(entries);
    if (count == 0) {
        *next_ifd_offset = 0;
        return offset;
    }

    // 保存IFD起始位置
    size_t ifd_start_offset = offset;

    // 写入条目数量
    uint16_t *ptr16 = (uint16_t*)(buffer + offset);
    *ptr16 = to_motorola16(count);
    printf("[EXIF_DEBUG] Writing IFD count: %d at offset %zu\n", count, offset);
    offset += 2;

    // 记录当前数据偏移
    size_t current_data_offset = data_offset;

    // 写入每个条目
    ExifEntry *current = entries;
    while (current) {
        printf("[EXIF_DEBUG] IFD entry tag=0x%04x, format=%d, components=%u\n",
           current->tag, current->format, current->components);
        // 标签
        ptr16 = (uint16_t*)(buffer + offset);
        *ptr16 = to_motorola16(current->tag);
        offset += 2;

        // 格式
        ptr16 = (uint16_t*)(buffer + offset);
        *ptr16 = to_motorola16(current->format);
        offset += 2;

        // 组件数量
        uint32_t *ptr32 = (uint32_t*)(buffer + offset);
        *ptr32 = to_motorola32(current->components);
        offset += 4;
        
        if (current->format == EXIF_FORMAT_ASCII) {
            printf("[EXIF_DEBUG] ASCII value: '%s'\n", (char*)current->data);
        }
        // 数据或数据偏移
        size_t data_size = current->dataSize;
        // 对于ASCII字符串，始终写入数据区以确保null终止符正确处理
        if (current->format == EXIF_FORMAT_ASCII) {
            ptr32 = (uint32_t*)(buffer + offset);
            // 计算相对于EXIF数据开始位置的偏移
            uint32_t rel_offset = current_data_offset;
            *ptr32 = to_motorola32(rel_offset);
            offset += 4;
            // 使用dataSize确保复制完整数据（包括null终止符）
            memcpy(buffer + current_data_offset, current->data, current->dataSize);
            current_data_offset += current->dataSize;
        } else if (data_size <= 4) {
            // 对于4字节或更小的数据，直接写入IFD条目
            memset(buffer + offset, 0, 4);
            memcpy(buffer + offset, current->data, data_size);
            offset += 4;
        } else {
            // 对于大于4字节的数据，写入偏移量
            ptr32 = (uint32_t*)(buffer + offset);
            // 计算相对于IFD0开始位置的偏移
            uint32_t rel_offset = current_data_offset - ifd0_offset;
            *ptr32 = to_motorola32(rel_offset);
            offset += 4;
            memcpy(buffer + current_data_offset, current->data, data_size);
            current_data_offset += data_size;
        }
        current = current->next;
    }

    // 写入下一个IFD的偏移
    uint32_t *ptr32 = (uint32_t*)(buffer + offset);
    *ptr32 = 0; // 没有IFD2
    offset += 4;

    if (next_ifd_offset) *next_ifd_offset = offset;
    return current_data_offset;
}

// 生成标准EXIF APP1区块
                              int exif_generate(ExifData *data) 
                              {
                                  if (!data) return 0;
                              
                                  if (data->buffer) {
                                      free(data->buffer);
                                      data->buffer = NULL;
                                      data->bufferSize = 0;
                                  }
                              
                                  int exif_count = count_entries(data->exifIfd);
                                  int gps_count = count_entries(data->gpsIfd);
                              
                                  if (exif_count > 0) {
                                      uint32_t exif_ifd_offset_be = to_motorola32(0);
                                      ExifEntry *exif_ifd_entry = exif_entry_create(0x8769, EXIF_FORMAT_LONG, 1, &exif_ifd_offset_be, 4);
                                      exif_add_entry(data, IFD0, exif_ifd_entry);
                                  }
                                  if (gps_count > 0) {
                                      uint32_t gps_ifd_offset_be = to_motorola32(0);
                                      ExifEntry *gps_ifd_entry = exif_entry_create(0x8825, EXIF_FORMAT_LONG, 1, &gps_ifd_offset_be, 4);
                                      exif_add_entry(data, IFD0, gps_ifd_entry);
                                  }
                              
                                  int ifd0_count = count_entries(data->ifd0);
                              
                                  size_t approx_size = 4096 + (ifd0_count + exif_count + gps_count) * 32;
                                  data->buffer = (uint8_t*)malloc(approx_size);
                                  if (!data->buffer) return 0;
                                  memset(data->buffer, 0, approx_size);
                              
                                  size_t offset = 0;
                                  memcpy(data->buffer + offset, "Exif\0\0", 6);
                                  offset += 6;
                              
                                  data->buffer[offset++] = 0x4D;
                                  data->buffer[offset++] = 0x4D;
                                  data->buffer[offset++] = 0x00;
                                  data->buffer[offset++] = 0x2A;
                                  // 先写入一个占位符，稍后修正
                                  uint32_t ifd0_offset_value = to_motorola32(0);
                                  memcpy(data->buffer + offset, &ifd0_offset_value, 4);
                                  offset += 4;
                              
                                  // 1. 先计算IFD0位置
                                  size_t ifd0_offset = offset;
    printf("[EXIF_DEBUG] IFD0 offset: %zu\n", ifd0_offset);
                                  
                                  // 2. 暂时跳过EXIF/GPS IFD偏移量修正，稍后在buffer中直接修改
                                  
                                  // 3. 计算IFD0数据区的偏移量 - 应该是IFD0条目的末尾
                                  size_t ifd0_data_offset = ifd0_offset + 2 + ifd0_count * 12 + 4;
    printf("[EXIF_DEBUG] IFD0 data offset: %zu, ifd0_count: %d\n", ifd0_data_offset, ifd0_count);
                                  int next_ifd_offset = 0;
                                  // 生成IFD0数据
    size_t ifd0_data_end = generate_ifd(data->buffer, ifd0_offset, data->ifd0, ifd0_data_offset, &next_ifd_offset, ifd0_offset);
    printf("[EXIF_DEBUG] IFD0 data end: %zu\n", ifd0_data_end);
                                  // 更新当前偏移量到IFD0数据区的末尾
                                  offset = ifd0_data_end;
                              
                                  // 2. EXIF IFD
                                  // 计算EXIF IFD的偏移量 - 应该是当前已写入数据的末尾
                                  size_t exif_ifd_offset = offset;
    printf("[EXIF_DEBUG] EXIF IFD offset: %zu\n", exif_ifd_offset);
                                  // 计算EXIF IFD数据区的偏移量 - 应该是EXIF IFD条目的末尾
                                  size_t exif_ifd_data_offset = exif_ifd_offset + (exif_count > 0 ? (2 + exif_count * 12 + 4) : 0);
    printf("[EXIF_DEBUG] EXIF IFD data offset: %zu\n", exif_ifd_data_offset);
                                  size_t exif_data_end = exif_ifd_offset;
                                  if (exif_count > 0) {
                                      int dummy = 0;
                                      exif_data_end = generate_ifd(data->buffer, exif_ifd_offset, data->exifIfd, exif_ifd_data_offset, &dummy, ifd0_offset);
        printf("[EXIF_DEBUG] EXIF data end: %zu\n", exif_data_end);
                                      // 更新当前偏移量到EXIF数据区的末尾
                                      offset = exif_data_end;
                                  }
                               
                                  // 3. GPS IFD
                                  // 计算GPS IFD的偏移量 - 应该是当前已写入数据的末尾
                                  size_t gps_ifd_offset = offset;
    printf("[EXIF_DEBUG] GPS IFD offset: %zu\n", gps_ifd_offset);
                                  // 计算GPS IFD数据区的偏移量 - 应该是GPS IFD条目的末尾
                                  size_t gps_ifd_data_offset = gps_ifd_offset + (gps_count > 0 ? (2 + gps_count * 12 + 4) : 0);
    printf("[EXIF_DEBUG] GPS IFD data offset: %zu\n", gps_ifd_data_offset);
                                  size_t gps_data_end = gps_ifd_offset;
                                  if (gps_count > 0) {
                                      int dummy = 0;
                                      gps_data_end = generate_ifd(data->buffer, gps_ifd_offset, data->gpsIfd, gps_ifd_data_offset, &dummy, ifd0_offset);
        printf("[EXIF_DEBUG] GPS data end: %zu\n", gps_data_end);
                                      // 更新当前偏移量到GPS数据区的末尾
                                      offset = gps_data_end;
                                  }
                              
                                  // 4. 修正EXIF/GPS IFD偏移量（在buffer中直接修改）
                                  if (exif_count > 0) {
                                      // 找到IFD0中的EXIF IFD条目并修正偏移量
                                      size_t ifd_entry_offset = ifd0_offset + 2; // 跳过条目数量
                                      for (int i = 0; i < ifd0_count; i++) {
                                          uint16_t tag = from_motorola16(*(uint16_t*)(data->buffer + ifd_entry_offset));
                                          if (tag == 0x8769) {
                                              uint32_t *offset_ptr = (uint32_t*)(data->buffer + ifd_entry_offset + 8);
                                              *offset_ptr = to_motorola32((uint32_t)exif_ifd_offset);
                                              printf("[EXIF_DEBUG] Fixed EXIF IFD offset: %zu -> %zu\n", exif_ifd_offset, exif_ifd_offset);
                                              break;
                                          }
                                          ifd_entry_offset += 12;
                                      }
                                  }
                                  if (gps_count > 0) {
                                      // 找到IFD0中的GPS IFD条目并修正偏移量
                                      size_t ifd_entry_offset = ifd0_offset + 2; // 跳过条目数量
                                      for (int i = 0; i < ifd0_count; i++) {
                                          uint16_t tag = from_motorola16(*(uint16_t*)(data->buffer + ifd_entry_offset));
                                          if (tag == 0x8825) {
                                              uint32_t *offset_ptr = (uint32_t*)(data->buffer + ifd_entry_offset + 8);
                                              *offset_ptr = to_motorola32((uint32_t)gps_ifd_offset);
                                              printf("[EXIF_DEBUG] Fixed GPS IFD offset: %zu -> %zu\n", gps_ifd_offset, gps_ifd_offset);
                                              break;
                                          }
                                          ifd_entry_offset += 12;
                                      }
                                  }
                              
                                  // 5. 修正IFD0偏移量（在EXIF头部的偏移量字段）
                                  uint32_t final_ifd0_offset = to_motorola32((uint32_t)ifd0_offset);
                                  memcpy(data->buffer + 10, &final_ifd0_offset, 4);
                                  printf("[EXIF_DEBUG] Fixed IFD0 offset: %zu -> %zu\n", ifd0_offset, ifd0_offset);
                              
                                  data->bufferSize = gps_count > 0 ? gps_data_end : (exif_count > 0 ? exif_data_end : ifd0_data_end);
                                  printf("[EXIF_DEBUG] Final buffer size: %zu\n", data->bufferSize);
                                  printf("[EXIF_DEBUG] EXIF buffer head: ");
                                  for (int i = 0; i < 32 && i < data->bufferSize; ++i) {
                                      printf("%02X ", data->buffer[i]);
                                  }
                                  printf("\n");
                                  return 1;
                              }


/* 将EXIF数据写入文件 */
int exif_write_file(ExifData *data, const char *filename) {
    if (!data || !filename || !data->buffer || data->bufferSize == 0) return 0;
    
    FILE *file = fopen(filename, "wb");
    if (!file) return 0;
    
    // 写入JPEG APP1标记 (0xFFE1)
    uint8_t app1_header[2] = {0xFF, 0xE1};
    fwrite(app1_header, 1, 2, file);
    
    // 写入APP1长度 (包括长度字段本身)
    uint16_t app1_length = to_motorola16(data->bufferSize + 2);
    fwrite(&app1_length, 1, 2, file);
    
    // 写入EXIF数据
    size_t written = fwrite(data->buffer, 1, data->bufferSize, file);
    
    fclose(file);
    return (written == data->bufferSize);
}

/* 获取生成的EXIF数据 */
uint8_t* exif_get_data(ExifData *data, size_t *size) {
    if (!data || !size) return NULL;
    
    *size = data->bufferSize;
    return data->buffer;
}
int file_copy_and_replace(const char *src, const char *dst) {
    FILE *in = fopen(src, "rb");
    if (!in) return 0;
    FILE *out = fopen(dst, "wb");
    if (!out) {
        fclose(in);
        return 0;
    }
    uint8_t buf[512];
    size_t n;
    while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
        fwrite(buf, 1, n, out);
    }
    fclose(in);
    fclose(out);
    remove(src);
    return 1;
}
int exif_insert_to_jpeg(const char *jpeg_filename, ExifData *data)
{
    if (!jpeg_filename || !data || !data->buffer || data->bufferSize == 0)
        return 0;

    // 1. 读取原JPEG文件到内存
    FILE *fp_in = fopen(jpeg_filename, "rb");
    if (!fp_in) return 0;
    fseek(fp_in, 0, SEEK_END);
    size_t file_size = ftell(fp_in);
    fseek(fp_in, 0, SEEK_SET);

    uint8_t *orig_buf = (uint8_t *)malloc(file_size);
    if (!orig_buf) {
        fclose(fp_in);
        return 0;
    }
    fread(orig_buf, 1, file_size, fp_in);
    fclose(fp_in);

    // 2. 查找SOI和APP0段
    size_t insert_pos = 2; // 默认SOI后
    if (file_size > 4 && orig_buf[0] == 0xFF && orig_buf[1] == 0xD8) {
        // 检查是否有APP0 (JFIF)
        if (orig_buf[2] == 0xFF && orig_buf[3] == 0xE0) {
            // APP0长度 (使用与写入时相同的字节序转换)
        // 正确读取APP0长度 (Motorola字节序)
        uint16_t app0_len = from_motorola16(*(uint16_t*)(orig_buf + 4));
        printf("[EXIF_DEBUG] APP0 length: %d (0x%04X)\n", app0_len, app0_len);
        insert_pos = 4 + app0_len;
        printf("[EXIF_DEBUG] Insert position after APP0: %zu\n", insert_pos);
        }
    } else {
        free(orig_buf);
        return 0; // 不是JPEG
    }

    // 3. 新建目标文件名
    char new_filename[128];
    snprintf(new_filename, sizeof(new_filename), "ai_snapshot_exif.jpg");

    FILE *fp_out = fopen(new_filename, "wb");
    if (!fp_out) {
        free(orig_buf);
        return 0;
    }

    // 4. 写入SOI和APP0前内容
    fwrite(orig_buf, 1, insert_pos, fp_out);

    // 5. 写入EXIF APP1段
    uint8_t app1_header[2] = {0xFF, 0xE1};
    fwrite(app1_header, 1, 2, fp_out);
    uint16_t app1_length = to_motorola16(data->bufferSize + 2);
    fwrite(&app1_length, 1, 2, fp_out);
    fwrite(data->buffer, 1, data->bufferSize, fp_out);

    // 6. 写入剩余JPEG内容
    fwrite(orig_buf + insert_pos, 1, file_size - insert_pos, fp_out);

    fclose(fp_out);
    free(orig_buf);

    printf("[EXIF] new jpeg with exif: %s\n", new_filename);
    return 1;
}
